package com.ruoyi.api.web;

import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.ruoyi.api.queue.RequestOrderQueue;
import com.ruoyi.api.vo.AsyncVo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.shop.domain.*;
import com.ruoyi.shop.service.*;
import com.ruoyi.shop.util.pay.PayStatus;
import com.ruoyi.shop.util.pay.UserOrderConstants;
import com.ruoyi.shop.util.pay.WXPayConstants;
import com.ruoyi.shop.util.pay.WxMiniProgramUtil;
import com.ruoyi.shop.vo.UserOrderVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

/**
 * @Author Alan Zhang
 * @Date 2021/10/6 16:14
 */
@Api(tags = "订单相关")
@RestController
@RequestMapping("/api/order")
public class ApiOrderController extends ApiBaseController{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private WxPayService wxService;
    @Autowired
    private IShopUserOrderService shopUserOrderService;
    @Autowired
    private IShopPaymentRecordService shopPaymentRecordService;
    @Autowired
    private IShopCouponCodeService shopCouponCodeService;
    @Autowired
    private IShopUserAddressService shopUserAddressService;
    @Autowired
    private IShopUserCartService shopUserCartService;
    @Autowired
    private RequestOrderQueue queue;

    @ApiOperation("用户可用优惠券")
    @ApiImplicitParam(paramType = "header", name = "token", value = "用户token", required = true, dataType = "String")
    @PostMapping("/userCoupon")
    public AjaxResult userCoupon(){
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        ShopCouponCode param = new ShopCouponCode();
        param.setUserId(shopUserOpenid.getUserId());
        param.setStatus(1);
        List<ShopCouponCode> list = shopCouponCodeService.selectShopCouponCodeList(param);
        return AjaxResult.success(list);
    }

    @ApiOperation("用户地址")
    @ApiImplicitParam(paramType = "header", name = "token", value = "用户token", required = true, dataType = "String")
    @PostMapping("/userAddress")
    public AjaxResult userAddress(){
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        ShopUserAddress param = new ShopUserAddress();
        param.setUserId(shopUserOpenid.getUserId());
        param.setWidthDefault(1);
        List<ShopUserAddress> userAddressList = shopUserAddressService.selectShopUserAddressList(param);
        return AjaxResult.success(userAddressList);
    }


    /**
     * 确认订单
     */
    @ApiOperation(value = "确认订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", name = "token", value = "用户token",required = true, dataType = "String")
    })
    @PostMapping("/confirm")
    public AjaxResult confirm() {
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        ShopCouponCode couponCodeParam = new ShopCouponCode();
        couponCodeParam.setUserId(shopUserOpenid.getUserId());
        couponCodeParam.setStatus(1);
        List<ShopCouponCode> couponCodeList = shopCouponCodeService.selectShopCouponCodeList(couponCodeParam);

        ShopUserAddress addressParam = new ShopUserAddress();
        addressParam.setUserId(shopUserOpenid.getUserId());
        addressParam.setWidthDefault(1);
        List<ShopUserAddress> userAddressList = shopUserAddressService.selectShopUserAddressList(addressParam);
        ShopUserAddress userAddress = userAddressList.get(0);

        ShopUserCart param = new ShopUserCart();
        param.setUserId(shopUserOpenid.getUserId());
        param.setSelected(1); //选中
        List<ShopUserCart> shopUserCartList = shopUserCartService.selectShopUserCartList(param);

        if (shopUserCartList == null || shopUserCartList.size() == 0) {
            throw new BusinessException("没有选择任何商品");
        }
        BigDecimal orderTotalAmount = new BigDecimal(0);
        BigDecimal couponAmount = new BigDecimal(0);
        for (ShopUserCart userCart : shopUserCartList) {
            ShopProduct shopProduct = userCart.getShopProduct();
            if (shopProduct.getStatus() != 1) {
                throw new BusinessException("商品 " + shopProduct.getTitle() + " 已经下架。");
            }

            // 如果查询出来的 stock == null，表示 可以购买任意件商品
            Long stock = shopProduct.getStock();
            if (stock != null && stock <= 0) {
                throw new BusinessException("商品 " + shopProduct.getTitle() + " 已经库存不足。");
            }

            if (stock != null && stock < userCart.getProductCount()) {
                throw new BusinessException("商品 " + shopProduct.getTitle() + " 已经库存不足，目前只能购买 " + stock + " 件商品。");
            }

            BigDecimal payAmount = shopProduct.getPrice().multiply(BigDecimal.valueOf(userCart.getProductCount()));
            orderTotalAmount = orderTotalAmount.add(payAmount);


        }

        return AjaxResult.success().put("userAddress",userAddress)
                .put("couponCodeList", couponCodeList)
                .put("payAmount",orderTotalAmount).put("couponAmount",couponAmount);
    }



    /**
     * 立即购买
     */
    @ApiOperation(value = "立即购买")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "header", name = "token", value = "用户token",required = true, dataType = "String"),
    })
    @PostMapping("/doBuy")
    public DeferredResult<Object> doBuy(@RequestBody UserOrderVo orderVo) {
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        orderVo.setUserId(shopUserOpenid.getUserId());
        orderVo.setNickname(shopUserOpenid.getNickname());

        System.out.println("[ OrderController ] 接到下单请求");
        logger.info("当前待处理订单数： {}", queue.getOrderQueue().size());

        AsyncVo<UserOrderVo, Object> vo = new AsyncVo<>();
        DeferredResult<Object> result = new DeferredResult<>();

        vo.setParams(orderVo);
        vo.setResult(result);

        try {
            queue.getOrderQueue().put(vo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("[ OrderController ] 返回下单结果");

        return result;
    }


    @ApiOperation("用户下订单")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
    })
    @PostMapping("/submit")
    public AjaxResult order(@RequestBody UserOrderVo userOrderVo) {
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        userOrderVo.setUserId(shopUserOpenid.getUserId());
        userOrderVo.setNickname(shopUserOpenid.getNickname());
        ShopUserOrder order = shopUserOrderService.genOrder(userOrderVo);

        return AjaxResult.success(order);
    }


    @ApiOperation("小程序请求支付")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(name = "payType", value = "支付类型", required = true, dataType = "String"),
    })
    @PostMapping("/payment")
    public AjaxResult payment(String orderNo, String payType) throws Exception {

        ShopUserOrder order = shopUserOrderService.selectShopUserOrderByOrderNo(orderNo);

        ShopPaymentRecord paymentRecord = shopPaymentRecordService.genPayOrder(order, payType);

        WxPayUnifiedOrderResult orderResult = reqUnifiedOrder(paymentRecord);

        if(WXPayConstants.SUCCESS.equals(orderResult.getResultCode())){
            String prepayId = orderResult.getPrepayId();

            String mchKey = wxService.getConfig().getMchKey();
            Map<String, String> map = WxMiniProgramUtil.paymentParams(prepayId, orderResult.getAppid(), mchKey);

            return AjaxResult.success(map).put("trxNo",paymentRecord.getTrxNo());
        } else {
            return AjaxResult.error("订单错误:"+orderResult.getErrCodeDes());
        }
    }


    /**
     * 统一下单 请求微信
     * @param paymentRecord
     * @return
     * @throws UnknownHostException
     * @throws WxPayException
     */
    private WxPayUnifiedOrderResult reqUnifiedOrder(ShopPaymentRecord paymentRecord) throws UnknownHostException, WxPayException {
        if(paymentRecord == null){
            throw new BusinessException("订单不存在");
        }
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(paymentRecord.getProductTitle());
        //获取日期 流水号
        orderRequest.setOutTradeNo("订单编号");
        //金额
        orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(paymentRecord.getPayAmount().toString()));//元转成分
        //openId
        orderRequest.setOpenid(paymentRecord.getThirdpartyUserOpenid());
        //小程序 标识
        orderRequest.setTradeType("JSAPI");
        //数据回调 地址
        String notifyUrl = wxService.getConfig().getNotifyUrl();
        logger.info("notifyUrl==={}", notifyUrl);
        orderRequest.setNotifyUrl(notifyUrl);
        //获取ip地址
        InetAddress address = InetAddress.getLocalHost();
        String hostAddress = address.getHostAddress();
        orderRequest.setSpbillCreateIp(hostAddress);
        long currentTime = System.currentTimeMillis() ;
        //交易开始时间
        //设置时差
        TimeZone timeZone = TimeZone.getTimeZone("GMT+8");
        TimeZone.setDefault(timeZone);
        String timeStart = new SimpleDateFormat("yyyyMMddHHmmss").format(currentTime);
        DateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
        orderRequest.setTimeStart(timeStart);
        //交易结束时间
        currentTime += 120*60*1000;
        String timeExpire = format1.format(new Date(currentTime));
        orderRequest.setTimeExpire(timeExpire);
        //订单 返回
        WxPayUnifiedOrderResult orderResult = wxService.unifiedOrder(orderRequest);

        return orderResult;
    }

    /**
     * 获取订单详情
     */
    @ApiOperation(value = "获取订单详情")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
            @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long"),
    })
    @PostMapping("/detail")
    public AjaxResult detail(Long orderId) {

        ShopUserOrder order = shopUserOrderService.selectShopUserOrderById(orderId);

        return AjaxResult.success(order);
    }


    @ApiOperation("用户取消支付")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query",name = "trxNo", value = "交易订单号", required = true, dataType = "String"),
    })
    @GetMapping("/payment/cancel")
    public AjaxResult orderCancel(String trxNo) {
        ShopUserOpenid shopUserOpenid = shopUserIdByToken();

        ShopPaymentRecord paymentRecord = shopPaymentRecordService.findByTrxNo(trxNo);

        if(!paymentRecord.getPayerUserId().equals(shopUserOpenid.getUserId())){
            return AjaxResult.error("用户不一致");
        }

        if (paymentRecord.isPayPre()) {

            ShopPaymentRecord entity = new ShopPaymentRecord();
            entity.setId(paymentRecord.getId());
            entity.setPayStatus(PayStatus.FAILURE.getStatus());
            entity.setRemark("用户取消");
            int rows = shopPaymentRecordService.updateShopPaymentRecord(entity);
            if(rows > 0){
                return AjaxResult.success("取消支付成功");
            }
        } else if(PayStatus.FAILURE.getStatus() == paymentRecord.getPayStatus()){
            return AjaxResult.error("已取消");
        } else{
            return AjaxResult.error("支付状态错误");
        }

        return AjaxResult.error();
    }


    @ApiOperation(value = "查询订单是否支付")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
            @ApiImplicitParam(name = "trxNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(name = "transactionId", value = "交易ID", required = false, dataType = "String"),
    })
    @GetMapping("/queryOrder")
    public AjaxResult queryOrder(@RequestParam(required = false) String transactionId,
                                            @RequestParam(required = false) String trxNo) throws WxPayException {

        ShopPaymentRecord shopPaymentRecord = shopPaymentRecordService.findByTrxNo(trxNo);
        if(shopPaymentRecord.isPaySuccess()){
            return AjaxResult.success("支付成功");
        } else {
            WxPayOrderQueryResult orderQueryResult = wxService.queryOrder(transactionId, trxNo);
            if (orderQueryResult.getResultCode().equals(WxPayConstants.ResultCode.SUCCESS)) {

                shopPaymentRecordService.paySuccess(orderQueryResult);
                return AjaxResult.success("支付成功").put("transactionId",orderQueryResult.getTransactionId());
            } else {
                return AjaxResult.error(orderQueryResult.getReturnMsg());
            }
        }
    }

    /**
     * 确认收货
     */
    @ApiOperation(value = "确认收货")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header",name = "token", value = "用户token", required = true, dataType = "String"),
            @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long"),
    })
    @PostMapping("/confirmOrder")
    public AjaxResult confirmOrder(Long orderId) {
        try {
            ShopUserOrder order = shopUserOrderService.selectShopUserOrderById(orderId);
            order.setTradeStatus(UserOrderConstants.TRADE_STATUS_COMPLETED);

            shopUserOrderService.updateShopUserOrder(order);
            return AjaxResult.success("确认收货成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error("提交失败");
    }
}
